﻿using System;
using System.Collections.Generic;
using Swift;
using Swift.Math;

namespace SCM
{
    /// <summary>
    /// 宝箱管理
    /// </summary>
    public class TreasureBoxRunner
    {
        // 获取 buff 的显示名称
        static StableDictionary<string, string> displayName = new StableDictionary<string, string>();
        public static string GetDisplayName(string type)
        {
            return displayName[type];
        }

        // 所属房间
        public Room Room { get; set; }

        static TreasureBoxRunner()
        {
            tbWeight["AddBiologyPower"] = 10;
            tbWeight["AddBiologyDefence"] = 10;
            tbWeight["AddMachinePower"] = 10;
            tbWeight["AddMachineDefence"] = 10;
            tbWeight["SubHp20"] = 10;
            tbWeight["AddMoney200"] = 10;
            tbWeight["AddSoldier3"] = 10;
            tbWeight["AddTank1"] = 10;
            tbWeight["AddBanshee1"] = 10;

            foreach (var w in tbWeight.Values)
                TotalWeight += w;

            displayName["AddBiologyPower"] = "生物攻击 +10%";
            displayName["AddBiologyDefence"] = "生物防御 +1";
            displayName["AddMachinePower"] = "机械攻击 +10%";
            displayName["AddMachineDefence"] = "机械防御 +1";
            displayName["SubHp20"] = "-20 hp";
            displayName["AddMoney200"] = "+200 资源";
            displayName["AddSoldier3"] = "+3 枪兵";
            displayName["AddTank1"] = "+1 坦克";
            displayName["AddBanshee1"] = "+1 女妖";
        }

        // 游戏时间流逝
        public void OnTimeElapsed(Fix64 te)
        {
            TryGenRandomTreasureBoxCarrier(te);
        }

        public void Clear()
        {
            tbActs.Clear();
        }

        // 随机产生一个宝箱投放机
        Fix64 nextTBCTime = 0;
        public void TryGenRandomTreasureBoxCarrier(Fix64 te)
        {
            // 期望平均每 90 产生一个宝箱，所以把 60s 作为下限，120s 作为上限
            if (nextTBCTime <= 0)
                nextTBCTime = Room.RandomNext(60, 120);
            
            nextTBCTime -= te / 1000;
            if (nextTBCTime <= 0)
            {
                var dropPt = new Vec2(
                    Room.RandomNext((int)(Room.MapSize.x / 10), (int)(Room.MapSize.x * 9 / 10)),
                    Room.RandomNext((int)(Room.MapSize.y / 10), (int)(Room.MapSize.y * 9 / 10)));

                if (!Room.FindNearestSpareSpace(dropPt,
                    (int)UnitConfiguration.GetDefaultConfig("TreasureBox").ShowSize,
                    0, out dropPt))
                    return;

                // 确定起止点和投放点
                nextTBCTime = 0;

                var mr = Room.MapSize.x > Room.MapSize.y ? Room.MapSize.x : Room.MapSize.y;
                var dir = Room.RandomNext(0, 360);
                var arc = dir * Fix64.Pi / 180;
                var d = mr * (new Vec2(Fix64.Cos(arc), Fix64.Sin(arc)));
                var fromPt = dropPt + d;
                var toPt = dropPt - d;

                var u = Room.AddNewUnit(null, "TreasureBoxCarrier", fromPt, 0);
                u.Dir = dir;
                u.MovePath.Add(dropPt);
                u.MovePath.Add(toPt);
            }
        }

        // 每个宝箱的用途
        StableDictionary<string, Action<Unit>> tbActs = new StableDictionary<string, Action<Unit>>();

        // 触发宝箱
        public void TriggerOne(Unit u, string uid)
        {
            tbActs[uid].SC(u);
            tbActs.Remove(uid);
        }

        // 创建随机宝箱
        static int TotalWeight = 0;
        static StableDictionary<string, int> tbWeight = new StableDictionary<string, int>();// 不同类型宝箱随机权重
        public Unit CreateRandomTreasureBox(Vec2 pos)
        {
            var w = Room.RandomNext(0, TotalWeight);
            foreach (var tb in tbWeight.Keys)
            {
                var tbW = tbWeight[tb];
                if (w <= tbW)
                    return CreateTreasureBox(tb, pos);
                else
                    w -= tbW;
            }

            return null;
        }

        // 在指定位置创建宝箱
        public Unit CreateTreasureBox(string tbType, Vec2 pos)
        {
            Action<Unit> act = null;

            switch (tbType)
            {
                case "AddBiologyPower":
                case "AddBiologyDefence":
                case "AddMachinePower":
                case "AddMachineDefence":
                    act = (u) => Room.CreateBuff(u.Player, tbType);
                    break;
                case "SubHp20":
                    act = (u) =>
                    {
                        var ts = Room.GetUnitsInCircleArea(pos, 80, (tar) => !tar.cfg.Unattackable);
                        foreach (var t in ts)
                            t.Hp -= 20;
                    };
                    break;
                case "AddHp10":
                    act = (u) =>
                    {
                        var ts = Room.GetUnitsInCircleArea(pos, 80, (tar) => !tar.cfg.Unattackable);
                        foreach (var t in ts)
                            t.Hp += 10;
                    };
                    break;
                case "AddMoney200":
                    act = (u) =>
                    {
                        u.Room.AddResource(u.Player, "Money", 200);
                    };
                    break;
                case "AddSoldier3":
                    act = (u) =>
                    {
                        FC.For(3, (i) =>
                        {
                            u.Room.AddNewUnit(null, "Soldier", u.Pos, u.Player);
                        });
                    };
                    break;
                case "AddTank1":
                    act = (u) =>
                    {
                        u.Room.AddNewUnit(null, "Tank", u.Pos, u.Player);
                    };
                    break;
                case "AddBanshee1":
                    act = (u) =>
                    {
                        u.Room.AddNewUnit(null, "Banshee", u.Pos, u.Player);
                    };
                    break;
            }

            if (act != null)
            {
                var u = Room.AddNewUnit(null, "TreasureBox", pos, 0);
                tbActs[u.UID] = act;
                u.Tag = tbType;
                return u;
            }

            return null;
        }
    }
}
